package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author atguigu-mqx
 * @Description TODO
 * @Date 2023/5/22 14:50
 * @Version 1.0
 */
@Service
public class CartServiceImpl implements CartService {
    /*
    1.  当购物车没有这个商品，直接添加
        如果有这个商品，则商品数量相加

    2.  每次添加购物车的时候，这个商品都是默认选中的

    3.  商品价格--展示最新的价格

    4.  需要排序：依据是商品的更新时间

    5.  单个商品的购买数量--限制 -- 限购操作
     */
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Override
    public void addToCart(Long skuId, Integer skuNum, String userId) {
        //  声明一个购物车key
        String cartKey = getCartKey(userId);
        //  从缓存中获取数据 hget key field;
        CartInfo cartInfoExist = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());
        //  判断这个商品在购物车是否存在
        if (null != cartInfoExist){
            //  说这个商品在缓存中存在.
            Integer sum = cartInfoExist.getSkuNum()+skuNum>200?200:cartInfoExist.getSkuNum()+skuNum;
            cartInfoExist.setSkuNum(sum);
            //  设置选中状态.
            cartInfoExist.setIsChecked(1);
            //            if (cartInfoExist.getIsChecked().intValue()!=1){
            //                cartInfoExist.setIsChecked(1);
            //            }
            cartInfoExist.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            //  给一个更新时间
            cartInfoExist.setUpdateTime(new Date());
            //  写回缓存
            //  this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfoExist);
        } else {
            //  当前这个商品不存在.
            cartInfoExist = new CartInfo();
            //  使用远程调用
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);

            //  赋值操作
            cartInfoExist.setUserId(userId);
            cartInfoExist.setSkuId(skuId);
            //  第一次添加页面只能最大输入200; 可以通过url 直接修改数据.
            Integer sum = skuNum>200?200:skuNum;
            cartInfoExist.setSkuNum(sum);
            //  这个是页面要显示的价格
            cartInfoExist.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            cartInfoExist.setCartPrice(skuInfo.getPrice());
            cartInfoExist.setSkuName(skuInfo.getSkuName());
            cartInfoExist.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfoExist.setCreateTime(new Date());
            cartInfoExist.setUpdateTime(new Date());

            //  写回缓存
            //  this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfoExist);
        }
        //  写回缓存
        this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfoExist);
        //  给过期时间：
        //  setKeyExpire(userId);
    }

    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        //  临时购物车集合数据
        List<CartInfo> cartInfoNoLoginList = new ArrayList();

        //  如果userId + userTempId; 可能会发生合并购物车.
        //  声明情况下只查看临时用户Id 的集合数据? 临时用户Id 不为空，用户Id 为空的时候！
        if (!StringUtils.isEmpty(userTempId)){
            //  获取到未登录购物车key
            String cartKey = this.getCartKey(userTempId);
            //  获取购物车列表 hvals key
            cartInfoNoLoginList = this.redisTemplate.opsForHash().values(cartKey);
        }

        //  当用户Id 为空的时候
        if (StringUtils.isEmpty(userId) && !CollectionUtils.isEmpty(cartInfoNoLoginList)){
            //  根据 updateTime 进行降序排序.
            cartInfoNoLoginList.sort((cartInfo1,cartInfo2)-> DateUtil.truncatedCompareTo(cartInfo2.getUpdateTime(),cartInfo1.getUpdateTime(), Calendar.SECOND));
            //  返回集合数据
            return cartInfoNoLoginList;
        }

        //  userId,userTempId 同时存在 并且 未登录购物车有数据，才会发生合并，否则不合并！
        //  登录购物车集合数据
        List<CartInfo> cartInfoLoginList = new ArrayList();
        if (!StringUtils.isEmpty(userId)){
            //  获取到登录购物车key
            String cartKey = this.getCartKey(userId);
            //  根据这个key 就可以获取到对应的数据.
            //            cartInfoLoginList = this.redisTemplate.opsForHash().values(cartKey);
            //  hset key field value;
            BoundHashOperations<String, String, CartInfo> boundHashOperations = this.redisTemplate.boundHashOps(cartKey);
            //  只有走了这个if条件才会发生合并操作。
            if (!CollectionUtils.isEmpty(cartInfoNoLoginList)){
                // boundHashOperations.get() ==  hget key field;
                // boundHashOperations.put(hk,hv); == hset key field value;
                // boundHashOperations.hasKey(field) == 判断这个field 是否存在.
                // boundHashOperations.values(); == hvals key
                for (CartInfo cartInfoNoLogin : cartInfoNoLoginList) {
                    //  判断登录中是否有未登录的skuId 17,18
                    if (boundHashOperations.hasKey(cartInfoNoLogin.getSkuId().toString())){
                        //  说明有skuId 相同的数据，则合并.
                        //  获取到登录的原有数据
                        CartInfo cartInfoLogin = boundHashOperations.get(cartInfoNoLogin.getSkuId().toString());
                        //  灵活处理 最新价格 ; 更新时间 cartInfoLogin.setUpdateTime(new Date());
                        //  商品数量相加;
                        Integer sum = cartInfoLogin.getSkuNum()+cartInfoNoLogin.getSkuNum()>200?200:cartInfoLogin.getSkuNum()+cartInfoNoLogin.getSkuNum();
                        cartInfoLogin.setSkuNum(sum);
                        //  合并之后，选中状态是什么? 选中状态
                        if (cartInfoNoLogin.getIsChecked().intValue()==1){
                            //                            if (cartInfoLogin.getIsChecked().intValue()==0){
                            //                              cartInfoLogin.setIsChecked(1); 只管登录为0的覆盖为1
                            //                            }
                            //  登录不管是0，还是1 统一都给1
                            cartInfoLogin.setIsChecked(1);
                        }
                        //  写回登录缓存.
                        boundHashOperations.put(cartInfoNoLogin.getSkuId().toString(),cartInfoLogin);
                    } else { // 19
                        //    表示当前未登录独有的数据. 直接添加到缓存.  111 -- 19  19 -- 合并到登录; 1 -- 19
                        //    不关选中状态是什么直接添加到登录集合.
                        cartInfoNoLogin.setUserId(userId);
                        cartInfoNoLogin.setCreateTime(new Date());
                        cartInfoNoLogin.setUpdateTime(new Date());
                        //     根据选中状态合并
                        //                        if (cartInfoNoLogin.getIsChecked().intValue()==1){
                        //                            cartInfoNoLogin.setUserId(userId);
                        //                            cartInfoNoLogin.setCreateTime(new Date());
                        //                            cartInfoNoLogin.setUpdateTime(new Date());
                        //                        }
                        //  写回登录数据
                        boundHashOperations.put(cartInfoNoLogin.getSkuId().toString(),cartInfoNoLogin);
                    }
                }
                //  删除未登录购物车集合数据
                this.redisTemplate.delete(this.getCartKey(userTempId));
            }
            //  未登录购物车集合为空，说明只有userId ; 查询登录购物车集合数据. 查询最终合并的数据
            cartInfoLoginList = boundHashOperations.values();
            //  如果为空，返回空数据。
            if (CollectionUtils.isEmpty(cartInfoLoginList)){
                return new ArrayList<>();
            }
            //  集合不为空，则根据 updateTime 进行降序排序.
            cartInfoLoginList.sort((cartInfo1,cartInfo2)-> DateUtil.truncatedCompareTo(cartInfo2.getUpdateTime(),cartInfo1.getUpdateTime(), Calendar.SECOND));
        }

        //  返回购物车集合列表
        return cartInfoLoginList;
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked, String userId) {
        //  hget key field  hset key field value;
        //  获取到购物车的key
        String cartKey = this.getCartKey(userId);
        //  获取购物项
        CartInfo cartInfo = (CartInfo) this.redisTemplate.boundHashOps(cartKey).get(skuId.toString());
        //  判断
        if (null != cartInfo){
            cartInfo.setIsChecked(isChecked);
        }
        //  写回缓存
        this.redisTemplate.boundHashOps(cartKey).put(skuId.toString(),cartInfo);
    }

    @Override
    public void allCheckCart(Integer isChecked, String userId) {
        //  先获取到购物车key
        String cartKey = this.getCartKey(userId);
        //  获取购物车列表 hvals key;
        List<CartInfo> cartInfoList = this.redisTemplate.boundHashOps(cartKey).values();
        //  创建一个Map 集合
        //        HashMap<String, CartInfo> hashMap = new HashMap<>();
        //        //  循环遍历 hmset key field value field value;
        //        if (!CollectionUtils.isEmpty(cartInfoList)){
        //            for (CartInfo cartInfo : cartInfoList) {
        //                //  修改选中状态
        //                cartInfo.setIsChecked(isChecked);
        //                //  hset key field value;
        //                //  this.redisTemplate.boundHashOps(cartKey).put(cartInfo.getSkuId().toString(),cartInfo);
        //                hashMap.put(cartInfo.getSkuId().toString(),cartInfo);
        //            }
        //        }
        //  cartInfo.getSkuId.toString()  cartInfo;
        Map<String, CartInfo> hashMap = cartInfoList.stream().map(cartInfo -> {
            //  修改选中状态
            cartInfo.setIsChecked(isChecked);
            return cartInfo;
        }).collect(Collectors.toMap(cartInfo -> cartInfo.getSkuId().toString(), cartInfo -> cartInfo));

        //  hmset key field value field value;  hmset key map
        this.redisTemplate.boundHashOps(cartKey).putAll(hashMap);
    }

    @Override
    public void deleteCart(Long skuId, String userId) {
        //  hdel key field;
        //  先获取到购物车key
        String cartKey = this.getCartKey(userId);
        //  del key;
        //  this.redisTemplate.delete(cartKey);
        this.redisTemplate.opsForHash().delete(cartKey,skuId.toString());
        //  this.redisTemplate.boundHashOps(cartKey).delete(skuId.toString());
    }

    @Override
    public void clearCart(String userId) {
        //  del key;
        //  先获取到购物车key
        String cartKey = this.getCartKey(userId);
        this.redisTemplate.delete(cartKey);
    }

    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        //  查询is_checked==1;
        //  获取到购物车的key
        String cartKey = this.getCartKey(userId);
        //  获取所有数据 hvals key;
        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        //  判断
        if (!CollectionUtils.isEmpty(cartInfoList)){
            //  循环遍历找出选中的商品  过滤使用filter;
            List<CartInfo> cartInfoCheckedList = cartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked().intValue()==1).collect(Collectors.toList());
            //  获取到选中的集合
            return cartInfoCheckedList;
        }
        //  默认返回
        return null;
    }

    //    private void setKeyExpire(String userId) {
        //        BigDecimal totalAmount = getDB(userId);
        //        if (0-10000){
        //            30day
        //        }else if(10001-30000){
        //            60day
        //        }else {
        //            365day;
        //        }
        //    }

    /**
     * 获取购物车key 方法
     * @param userId
     * @return
     */
    private String getCartKey(String userId) {
        //  返回购物车的key = user:userId:cart
        return RedisConst.USER_KEY_PREFIX+ userId +RedisConst.USER_CART_KEY_SUFFIX;
    }

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,4,5,2,9,8);
        list.sort((o1, o2) -> o1-o2);
        System.out.println(list);

    }


}
